<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Bar chart object using D3.js

Released using BSD License, same as that used by D3.js.
-->
<html>
<head>
	<title>Bar Chart</title>
	<meta http-equiv="X-UA-Compatible" content="IE=9">
	<meta charset='utf-8'>
	<!--<script src="http://d3js.org/d3.v3.min.js"></script>-->
	<script src="js/d3.v3-3.3.6.js"></script>
</head>
<body>
 
<!--<div id="chart" style="width:1000px; height:400px;"></div>-->
<div id="chart" style="width:1000; height:600;"></div>
 
<script>
/* initial methods
function getElementWidth(elem)
{
	return parseInt(elem.style.width);
}
 
function getElementHeight(elem)
{
	return parseInt(elem.style.height);
}
*/
 
/* get style of element */
/* http://atomicrobotdesign.com/blog/javascript/get-the-style-property-of-an-element-using-javascript/ */
function getStyle(elem, prop)
{
    return window.getComputedStyle(elem, null).getPropertyValue(prop);
}
 
function getElementComputedStyleValue(elem, property, defaultValue)
{
	var retValue = defaultValue;
	var value = getStyle(elem, property);
	
	if ( value != null && value != "" && value == 0 ) {
		retValue = parseInt(value);
	}
	
	return retValue;
}
 
function BarChart3(chartID)
{
	/* object variables */
	this.version = "1.0.0";
	this.id = chartID;
	
	/* object methods */
	this.draw = function(divID, dataFormat, dataSource, dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName)
	{
		var data = null;
		if ( dataFormat == "csv" ) {
			if ( dataSource == "text" ) {
				data = d3.csv.parse(dataSet);
			} else if ( dataSource == "url" ) {
				data = dataSet;
			}
		} else if ( dataFormat == "tsv" ) {
			data = dataSet;
		} else if ( dataFormat == "json" ) {
			data = dataSet;
		}
		
		if ( divID == null || divID == "") {
			divID = "body";
		}
		
		/* get the width and height of the element, to set height and width of chart accordingly */
		var selectedElement = document.getElementById(divID);
		chartConfig.width = getElementComputedStyleValue(selectedElement, "width", chartConfig.width);
		chartConfig.height = getElementComputedStyleValue(selectedElement, "height", chartConfig.height);
		
		var chartWidth = chartConfig.width - (chartConfig.barLabelWidth + chartConfig.valueLabelWidth + chartConfig.paddingY);
		var chartHeight = chartConfig.height - chartConfig.gridLabelHeight - chartConfig.chartOffsetY;
		chartConfig.barHeight = chartHeight / data.length;
		
		// accessor functions
		var barLabel = function(d) { return d[labelColumnName]; };
		var barValue = function(d) { return parseFloat(d[dataColumnName]); };
		
		// scales
		var x = d3.scale.linear().domain([0, d3.max(data, barValue)]).range([0, chartWidth]);
		//var yScale = d3.scale.ordinal().domain(d3.range(0, data.length)).rangeBands([0, data.length * chartConfig.barHeight]);
		var yScale = d3.scale.ordinal().domain(d3.range(0, data.length)).rangeBands([0, chartHeight]);
		var y = function(d, i) { return yScale(i); };
		var yText = function(d, i) { return y(d, i) + yScale.rangeBand() / 2; };
		
		// svg container element
		var chart = d3.select('#' + divID).append("svg")
			.attr('width', chartConfig.width)
			.attr('height', chartConfig.height);
			
		// Ruler text and grid lines
		if ( gridLineConfig.showLabels == true || gridLineConfig.showLines == true ) {
			var gridContainer = chart.append('g')
				.attr('transform', 'translate(' + chartConfig.barLabelWidth + ',' + chartConfig.gridLabelHeight + ')');
				
			// grid line labels
			if ( gridLabelConfig.showLabels == true ) {
				gridContainer.selectAll("text")
					.data(x.ticks(gridLineConfig.numTicks)) // deliberately using gridLineConfig.numTicks
					.enter()
					.append("text")
					.attr("x", x)
					.attr("dy", gridLabelConfig.offsetY)
					.attr("text-anchor", gridLabelConfig.alignment)
					.attr("font-size", gridLabelConfig.fontSize)
					.style("font-family", gridLabelConfig.font)
					.style("fill", gridLabelConfig.fillColor)
					.style("stroke", gridLabelConfig.strokeColor)
					.text(String);
			}
			
			// grid lines
			if ( gridLineConfig.showLines == true ) {
				gridContainer.selectAll("line")
					.data(x.ticks(gridLineConfig.numTicks))
					.enter()
					.append("line")
					.attr("x1", x)
					.attr("x2", x)
					.attr("y1", 0)
					.attr("y2", yScale.rangeExtent()[1] + chartConfig.chartOffsetY)
					.style("fill", gridLineConfig.fillColor)
					.style("stroke", gridLineConfig.strokeColor);
			}
		}
			
		// bar labels
		var labelsContainer = chart.append('g')
			.attr('transform', 'translate(' + (chartConfig.barLabelWidth - chartConfig.barLabelPadding) + ',' + (chartConfig.gridLabelHeight + chartConfig.chartOffsetY) + ')');
		labelsContainer.selectAll('text')
			.data(data)
			.enter()
			.append('text')
			.attr('y', yText)
			.attr('stroke', barLabelConfig.strokeColor)
			.attr('fill', barLabelConfig.fillColor)
			.attr("dy", barLabelConfig.yOffset)
			.attr('text-anchor', barLabelConfig.alignment)
			.attr("font-size", barLabelConfig.fontSize)
			.style("font-family", barLabelConfig.font)
			.style("fill", barLabelConfig.fillColor)
			.style("stroke", barLabelConfig.strokeColor)
			.text(barLabel);
			
		// bars
		var barsContainer = chart.append('g')
			.attr('transform', 'translate(' + chartConfig.barLabelWidth + ',' + (chartConfig.gridLabelHeight + chartConfig.chartOffsetY) + ')');
		barsContainer.selectAll("rect").data(data).enter().append("rect")
			.attr('y', y)
			.attr('height', yScale.rangeBand())
			.attr('width', function(d) { return x(barValue(d)); })
			.attr('stroke', barConfig.strokeColor)
			.style("fill",
				function(d, i) {
					if ( barConfig.fillColor == "single" ) {
						return barConfig.fillColorScale;
					} else if ( barConfig.fillColor == "range" ) {
						var idx = i % barConfig.fillColorScale.length;
						return barConfig.fillColorScale[idx];
					} else if ( barConfig.fillColor == "scale" ) {
						return barConfig.fillColorScale(i);
					}
				}
			);
		
		// bar value labels
		if ( barValueLabelConfig.showLabels == true ) {
			barsContainer.selectAll("text")
				.data(data)
				.enter()
				.append("text")
				.attr("x", function(d) { return x(barValue(d)); })
				.attr("y", yText)
				.attr("dx", barValueLabelConfig.paddingX)
				.attr("dy", barValueLabelConfig.paddingY)
				.attr("text-anchor", barValueLabelConfig.alignment)
				.attr("font-size", barValueLabelConfig.fontSize)
				.style("font-family", barValueLabelConfig.font)
				.style("fill", barValueLabelConfig.fillColor)
				.style("stroke", barValueLabelConfig.strokeColor);
			if ( barValueLabelConfig.roundDecimalsPlaces != null || barValueLabelConfig.roundDecimalsPlaces > 0 ) {
				barsContainer.selectAll("text")
					.data(data).text(function(d) { return d3.round(barValue(d), barValueLabelConfig.roundDecimalsPlaces); });
			}
		}
		
		// x-axis line
		if ( chartConfig.showXAxis == true ) {
			barsContainer.append("line")
				.attr("x1", 0)
				.attr("x2", chartWidth)
				.attr("y1", 0)
				.attr("y2", 0)
				.style("fill", chartConfig.xAxisFillColor)
				.style("stroke", chartConfig.xAxisStrokeColor);
		}
		
		// y-axis line
		if ( chartConfig.showYAxis == true ) {
			barsContainer.append("line")
				.attr("x1", 0)
				.attr("x2", 0)
				.attr("y1", 0)
				.attr("y2", chartHeight)
				.style("fill", chartConfig.yAxisFillColor)
				.style("stroke", chartConfig.yAxisStrokeColor);
		}
	},
	this.draw_CSV_URL = function(chartObject, divID, dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName)
	{
		d3.csv(dataSet, function(data) {
			chartObject.draw(divID, "csv", "url", data, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
		});
	},
	this.draw_TSV_URL = function(chartObject, divID, dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName)
	{
		d3.tsv(dataSet, function(data) {
			chartObject.draw(divID, "tsv", "url", data, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
		});
	},
	this.draw_JSON_Variable = function(chartObject, divID, dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName)
	{
		barChart.draw(divID, "json", "variable", dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	},
	this.draw_JSON_URL = function(chartObject, divID, dataSet, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName)
	{
		d3.json(dataSet, function(data) {
			chartObject.draw(divID, "json", "url", data.values, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
		});
	}
}
</script>
 
<script id="csv" type="text/csv">Name,Population (mill),Average Life Expectancy,Area (1000 sq mi),Continent
Canada,33.9,80.7,3854.085,America
US,308.3,78.2,3784.191,America
Germany,82.3,79.4,137.847,Europe
Russia,141.9,65.5,6601.668,Europe
Mexico,108.4,76.06,758.449,America
Brazil,193.3,71.99,3287.612,America
Spain,46.9,80.9,195.365,Europe
France,65.4,80.98,244.339,Europe
China,1339,73,3705.407,Asia
Australia,22.4,81.2,2969.907,Australia
UK,62,79.4,93.800,Europe
Italy,60.3,80.5,116.346,Europe
India,1184,64.7,1236.085,Asia
Japan,127.4,82.6,145.920,Asia
Iceland,0.3,81.8,40.000,Europe
Portugal,10.6,78.1,35.560,Europe
South Africa,50,49.3,471.445,Africa
Egypt,78.9,71.3,387.000,Africa
Sweden,9.3,80.9,170.410,Europe
</script>
<script id="tsv" type="text/tsv">Name Population (mill)	Average Life Expectancy	Area (1000 sq mi)	Continent
Canada	33.9	80.7	3854.085	America
US	308.3	78.2	3784.191	America
Germany	82.3	79.4	137.847	Europe
Russia	141.9	65.5	6601.668	Europe
Mexico	108.4	76.06	758.449	America
Brazil	193.3	71.99	3287.612	America
Spain	46.9	80.9	195.365	Europe
France	65.4	80.98	244.339	Europe
China	133973	3705.407	Asia
Australia	22.4	81.2	2969.907	Australia
UK	62	79.4	93.800	Europe
Italy60.3	80.5	116.346	Europe
India	118464.7	1236.085	Asia
Japan	127.4	82.6	145.920	Asia
Iceland	0.3	81.8	40.000	Europe
Portugal	10.6	78.1	35.560	Europe
South Africa50	49.3	471.445	Africa
Egypt	78.9	71.3	387.000	Africa
Sweden	9.3	80.9	170.410	Europe
</script>
 
 
<script>
var values2 = [
	{ "Name": "Canada", "Population (mill)": 33.9, "Average Life Expectancy": 80.7, "Area (1000 sq mi)": 3854.085, "Continent": "America" },
	{ "Name": "US", "Population (mill)": 308.3, "Average Life Expectancy": 78.2, "Area (1000 sq mi)": 3784.191, "Continent": "America" },
	{ "Name": "Germany", "Population (mill)": 82.3, "Average Life Expectancy": 79.4, "Area (1000 sq mi)": 137.847, "Continent": "Europe" },
	{ "Name": "Russia", "Population (mill)": 141.9, "Average Life Expectancy": 65.5, "Area (1000 sq mi)": 6601.668, "Continent": "Europe" },
	{ "Name": "Mexico", "Population (mill)": 108.4, "Average Life Expectancy": 76.06, "Area (1000 sq mi)": 758.449, "Continent": "America" },
	{ "Name": "Brazil", "Population (mill)": 193.3, "Average Life Expectancy": 71.99, "Area (1000 sq mi)": 3287.612, "Continent": "America" },
	{ "Name": "Spain", "Population (mill)": 46.9, "Average Life Expectancy": 80.9, "Area (1000 sq mi)": 195.365, "Continent": "Europe" },
	{ "Name": "France", "Population (mill)": 65.4, "Average Life Expectancy": 80.98, "Area (1000 sq mi)": 244.339, "Continent": "Europe" },
	{ "Name": "China", "Population (mill)": 1339, "Average Life Expectancy": 73, "Area (1000 sq mi)": 3705.407, "Continent": "Asia" },
	{ "Name": "Australia", "Population (mill)": 22.4, "Average Life Expectancy": 81.2, "Area (1000 sq mi)": 2969.907, "Continent": "Australia" },
	{ "Name": "UK", "Population (mill)": 62, "Average Life Expectancy": 79.4, "Area (1000 sq mi)": 93.800, "Continent": "Europe" },
	{ "Name": "Italy", "Population (mill)": 60.3, "Average Life Expectancy": 80.5, "Area (1000 sq mi)": 116.346, "Continent": "Europe" },
	{ "Name": "India", "Population (mill)": 1184, "Average Life Expectancy": 64.7, "Area (1000 sq mi)": 1236.085, "Continent": "Asia" },
	{ "Name": "Japan", "Population (mill)": 127.4, "Average Life Expectancy": 82.6, "Area (1000 sq mi)": 145.920, "Continent": "Asia" },
	{ "Name": "Iceland", "Population (mill)": 0.3, "Average Life Expectancy": 81.8, "Area (1000 sq mi)": 40.000, "Continent": "Europe" },
	{ "Name": "Portugal", "Population (mill)": 10.6, "Average Life Expectancy": 78.1, "Area (1000 sq mi)": 35.560, "Continent": "Europe" },
	{ "Name": "South Africa", "Population (mill)": 50, "Average Life Expectancy": 49.3, "Area (1000 sq mi)": 471.445, "Continent": "Africa" },
	{ "Name": "Egypt", "Population (mill)": 78.9, "Average Life Expectancy": 71.3, "Area (1000 sq mi)": 387.000, "Continent": "Africa" },
	{ "Name": "Sweden", "Population (mill)": 9.3, "Average Life Expectancy": 80.9, "Area (1000 sq mi)": 170.410, "Continent": "Europe" }
];
 
	
var chartConfig = {
	width: 1200,
	height: 400,
	valueLabelWidth: 40, // space reserved for value labels (right)
	barHeight: 20, // height of one bar
	barLabelWidth: 100, // space reserved for bar labels
	barLabelPadding: 5, // padding between bar and bar labels (left)
	gridLabelHeight: 18, // space reserved for gridline labels
	chartOffsetY: 0, // space between start of grid and first bar
	//maxBarWidth: 500, // width of the bar with the max value
	paddingY: 200,
	showXAxis: true,
	xAxisFillColor: "none",
	xAxisStrokeColor: "#000000",
	showYAxis: true,
	yAxisFillColor: "none",
	yAxisStrokeColor: "#000000"
};
 
var gridLineConfig = {
	showLines: true,
	numTicks: 10,
	fillColor: 'none',
	strokeColor: '#ccc'
};
 
var gridLabelConfig = {
	showLabels: true,
	offsetY: -3,
	fontSize: 12,
	font: "sans-serif",
	alignment: 'middle',
	fillColor: 'black',
	strokeColor: 'none'
};
 
var barLabelConfig = {
	fontSize: 12,
	font: "sans-serif",
	fillColor: "#000000",
	strokeColor: "none",
	fillColor: 'black',
	strokeColor: 'none',
	yOffset: ".35em",
	alignment: 'end'
};
 
var colorScale = d3.scale.category20();
 
var barConfig = {
	strokeColor: 'white',
	fillColor: "scale", // "single", "range", "scale"
	//fillColorScale: "steelblue"
	//fillColorScale: ["steelblue", "red"]
	fillColorScale: colorScale
};
 
var barValueLabelConfig = {
	showLabels: true,
	fontSize: 12,
	font: "sans-serif",
	fillColor: 'black',
	strokeColor: 'none',
	alignment: 'start',
	roundDecimalsPlaces: 2,
	paddingX: 3,
	paddingY: ".35em"
};
 
var labelColumnName = 'Name';
var dataColumnName = 'Population (mill)';
var divID = "chart";
 
var barChart = new BarChart3("b1");
 
var dataFormat = "csv"; // "tsv" / "json" / "csv"
var dataSource = "text"; // "url" / "text" / "variable" (only for json)
if ( dataFormat == "csv" ) {
	if ( dataSource == "text" ) {
		barChart.draw(divID, "csv", "text", d3.select('#csv').text(), chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	} else if ( dataSource == "url" ) {
		barChart.draw_CSV_URL(barChart, divID, "data/bar-column-chart.csv", chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	}
} else if ( dataFormat == "tsv" ) {
	if ( dataSource == "text" ) {
		// not working as expected
		//barChart.draw(divID, "tsv", "text", d3.select('#tsv').text(), chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
		alert("'tsv - text' functionality not implemented");
	} else if ( dataSource == "url" ) {
		barChart.draw_TSV_URL(barChart, divID, "data/bar-column-chart.tsv", chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	}
} else if ( dataFormat == "json" ) {
	if ( dataSource == "variable" ) {
		barChart.draw_JSON_Variable(barChart, divID, values2, chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	} else if ( dataSource == "url" ) {
		barChart.draw_JSON_URL(barChart, divID, "data/bar-column-chart.json", chartConfig, gridLineConfig, gridLabelConfig, barLabelConfig, barConfig, labelColumnName, dataColumnName);
	}
}
</script>
</body>
</html>
